<!DOCTYPE html>
<html lang="en">
<head>
  <script src="node_modules/@picovoice/web-voice-processor/dist/iife/index.js"></script>
  <script src="node_modules/@picovoice/porcupine-web/dist/iife/index.js"></script>
  <script src="keywords/porcupineKeywords.js"></script>
  <script src="models/porcupineModel.js"></script>
  <script type="application/javascript">

    let porcupine = null;

    window.addEventListener('load', function () {
      let usingBuiltIns = false;
      if(porcupineKeywords.length === 0 && porcupineModel.publicPath.endsWith("porcupine_params.pv")) {
        usingBuiltIns = true;
        for(const k in PorcupineWeb.BuiltInKeyword) {
          porcupineKeywords.push(k);
        }
      }

      let select = document.getElementById("keywords");
      for(let i = 0; i < porcupineKeywords.length; i++) {
        let el = document.createElement("option");
        el.textContent = usingBuiltIns ? PorcupineWeb.BuiltInKeyword[porcupineKeywords[i]] : porcupineKeywords[i].label;
        el.value = `${i}`;
        select.appendChild(el);
      }
    });

    function writeMessage(message) {
      console.log(message);
      document.getElementById("status").innerHTML = message;
    }

    function porcupineErrorCallback(error) {
      writeMessage(error);
    }

    function porcupineKeywordCallback(detection) {
      const time = new Date();
      const message = `keyword detected at ${time.toLocaleTimeString()}: ${detection.label} (index = ${detection.index})`
      console.log(message);
      document.getElementById("result").innerHTML = message;
    }

    async function startPorcupine(accessKey, keywordIndex) {
      if (window.WebVoiceProcessor.WebVoiceProcessor.isRecording) {
        await window.WebVoiceProcessor.WebVoiceProcessor.unsubscribe(porcupine);
        await porcupine.terminate();
      }

      writeMessage("Porcupine is loading. Please wait...");
      try {
        porcupine = await PorcupineWeb.PorcupineWorker.create(
          accessKey,
          [porcupineKeywords[keywordIndex]],
          porcupineKeywordCallback,
          porcupineModel
        );

        writeMessage("Porcupine worker ready!");

        writeMessage(
          "WebVoiceProcessor initializing. Microphone permissions requested ..."
        );
        await window.WebVoiceProcessor.WebVoiceProcessor.subscribe(porcupine);

        writeMessage("WebVoiceProcessor ready and listening!");
      } catch (err) {
        porcupineErrorCallback(err);
      }
    }
  </script>
</head>
<body>
<h1>Porcupine Web Demo</h1>
<p>This demo uses Porcupine for Web and the WebVoiceProcessor to:</p>
<ol>
  <li>
    Create an instance of Porcupine that listens for the selected keyword.
  </li>
  <li>
    Acquire microphone (& ask permission) data stream and convert to voice
    processing format (16kHz 16-bit linear PCM). The down-sampled audio is
    forwarded to the Porcupine engine. The audio <i>does not</i> leave the
    browser: all processing is occurring via the Porcupine WebAssembly code.
  </li>
  <li>
    Listen for keyword detection events from the Porcupine engines and output them to the page.
  </li>
</ol>
<p>After entering the AccessKey, click the "Start Porcupine" button.</p>
<p>While listening you can try out different keywords using the "Keywords" dropdown.</p>
<hr/>
<label for="accessKey"
>AccessKey obtained from
  <a href="https://console.picovoice.ai/">Picovoice Console</a>:</label
>
<input type="text" id="accessKey" name="accessKey"/>
<input
        type="button"
        id="submit"
        value="Start Porcupine"
        onclick="startPorcupine(
                document.getElementById('accessKey').value,
                parseInt(document.getElementById('keywords').value))"
/>
<br>
<br>
<label for="keywords">Keyword:</label>
<select
        id="keywords"
        name="keywords"
        onchange="if (window.WebVoiceProcessor.WebVoiceProcessor.isRecording) { startPorcupine(
                document.getElementById('accessKey').value,
                parseInt(document.getElementById('keywords').value)) }"></select>
<hr/>
<div id="status" style="white-space: pre;"></div>
<br>
<div id="result"></div>
</body>
</html>
